package slowquery

import (
	"context"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type GormLogger struct {
	SlowThreshold time.Duration
	LogLevel      logger.LogLevel
	Colorful      bool
}

type MysqlConn struct {
	Host         string
	Port         int
	Username     string
	Password     int
	DatabaseName string
	conn         *gorm.DB
}

var LogSrv *GormLogger
var mysqlConn_ *MysqlConn

// NewGormLogger 实例化日志配置
func NewGormLogger() *GormLogger {
	return &GormLogger{
		SlowThreshold: 1 * time.Millisecond,
		LogLevel:      logger.Warn,
		Colorful:      true,
	}
}

type User struct {
	Id   int64  `gorm:"column:user_id;primary_key;types:bigint(20)" json:"user_id"`
	Name string `gorm:"column:name;types:varchar(100);primary_key;" json:"name"`
}

func (f *User) TableName() string {
	return "fk_user"
}

// LogMode 实现GORM的Logger接口
func (l *GormLogger) LogMode(level logger.LogLevel) logger.Interface {
	return l
}

// Info 实现gorm模型的接口
func (l *GormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
	Now := time.Now().Format("2006-01-02 15:04:05")
	log.Printf("[Info][%v]: %s | %v \n", Now, msg, data)
}

func (l *GormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
	Now := time.Now().Format("2006-01-02 15:04:05")
	log.Printf("[Warn][%v]: %s | %v \n", Now, msg, data)
}

func (l *GormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
	Now := time.Now().Format("2006-01-02 15:04:05")
	log.Printf("[Error][%v]: %s | %v \n", Now, msg, data)
}

func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
	elapsed := time.Since(begin)
	sql, rows := fc()
	if err != nil {
		log.Printf("Error: %v\n", err)
	}
	if elapsed > l.SlowThreshold {
		log.Printf("[warn][slow query]: duration: %v, %d row affected,\n[sql]: %s;\n", elapsed, rows, sql)
	}
}

func getProjectDir() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		fmt.Println(err)
	}
	projectDir := strings.Replace(dir, "\\", "/", -1)
	return fmt.Sprintf("%s/log/", projectDir)
}

func WriteLogFile() {
	logFilePath := getProjectDir() + "/slow_query.log"
	logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalln("Failed to open log file", logFilePath, ":", err)
	}
	log.SetOutput(logFile)
}

func InitMysqlConn() error {
	WriteLogFile()
	mysqlConn_ = &MysqlConn{
		Host:         "82.156.87.105",
		Port:         3306,
		Username:     "homed",
		Password:     123456,
		DatabaseName: "fk_school",
	}
	if err := mysqlConn_.connect(); err != nil {
		log.Fatalln("Failed to connect to mysql:", err)
	}
	mysqlConn_.CreateTables()
	return nil
}

func (m *MysqlConn) connect() error {
	dns := fmt.Sprintf("%s:%d@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", m.Username, m.Password, m.Host, m.Port, m.DatabaseName)
	db, err := gorm.Open(mysql.Open(dns), &gorm.Config{
		Logger: NewGormLogger(),
	})
	if err != nil {
		return fmt.Errorf("mysql connect fail,err:%v", err)
	}
	sqlDB, err := db.DB()
	if err != nil {
		return fmt.Errorf("sqlDB connect fail,err:%v", err)
	}
	sqlDB.SetMaxIdleConns(1000)
	sqlDB.SetMaxOpenConns(100)
	sqlDB.SetConnMaxLifetime(30) //最大生存时间
	m.conn = db
	fmt.Println("mysql connect success!")
	return nil
}

func (m *MysqlConn) GetConn() *gorm.DB {
	return m.conn
}

func GetConn() *gorm.DB {
	return mysqlConn_.GetConn()
}

func (m *MysqlConn) CreateTables() {
}
